`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date: 03/27/2025 10:31:34 AM
// Design Name: 
// Module Name: tb_test
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//////////////////////////////////////////////////////////////////////////////////


module tb_test;

    // Parameters
    parameter ADDR_WIDTH = 32;
    parameter DATA_WIDTH = 32;
    reg                               aclk              = 0     ;
    reg                               s_axis_tvalid     = 0     ;
    reg                               m_axis_tready     = 0     ;
    wire         [DATA_WIDTH-1:0]     m_axis_tdata              ;

    wire         [DATA_WIDTH-1:0]     m_axis_tdata_w            ;
    reg                               m_axis_tready_w   = 0     ;
    wire                              m_axis_tvalid_w           ;
    // AXI Signals
    reg                               s_axi_aclk        = 0     ;
    reg                               s_axi_aresetn     = 1     ;
    // AXI Write Address Channel
    reg                               s_axi_awvalid     = 0     ;
    reg          [ADDR_WIDTH-1:0]     s_axi_awaddr      = 0     ;
    reg                    [ 2:0]     s_axi_awprot      = 3'b010;
    wire                              s_axi_awready             ;
    // AXI Write Data Channel
    reg                               s_axi_wvalid      = 0     ;
    reg          [DATA_WIDTH-1:0]     s_axi_wdata       = 0     ;
    reg          [(DATA_WIDTH/8)-1:0] s_axi_wstrb       = 0     ;
    wire                              s_axi_wready              ;
    // AXI Write Response Channel
    wire                              s_axi_bvalid              ;
    wire                   [ 1:0]     s_axi_bresp               ;
    reg                               s_axi_bready      = 0     ;

    reg                               s_axi_arvalid     = 0     ;
    reg          [ADDR_WIDTH-1:0]     s_axi_araddr      = 0     ;
    reg                    [ 2:0]     s_axi_arprot      = 0     ;
    wire                              s_axi_arready             ;

    wire                              s_axi_rvalid              ;
    wire         [DATA_WIDTH-1:0]     s_axi_rdata               ;
    wire                   [ 1:0]     s_axi_rresp               ;
    reg                               s_axi_rready      = 0     ;

    localparam Fs = 245760; // 245.76 Msps
    localparam Ts = 1;     // 1 ms
    reg  [DATA_WIDTH-1:0] data_ram[0:Fs*Ts-1]; // 10ms 245.76Msps data
    
    integer i;
    integer file_handle;
    initial begin
        file_handle = $fopen("/home/fulin.zhang/ctrx_5g/projects/k7/xpt60/iq_data.txt", "r");
        if (file_handle) begin
            $fclose(file_handle);
            $readmemh("/home/fulin.zhang/ctrx_5g/projects/k7/xpt60/iq_data.txt", data_ram);
            $display("Successful loading iq_data.txt to RAM");
            for(i=0; i<32; i=i+1) begin
                $display("data_ram[%d]: %h", i, data_ram[i]); 
            end
        end else begin
            $display("[WARNING] iq_data.txt not found");
        end
    end

    // Clock Generation
    initial begin
        s_axi_aclk = 0;
        //forever #5.000 s_axi_aclk = ~s_axi_aclk; // 100 MHz clock
        forever #2.035 s_axi_aclk = ~s_axi_aclk; // 245.76 MHz clock
    end

    initial begin
        aclk = 0;
        //forever #1.808 aclk = ~aclk; // 276.48 MHz clock
        //forever #1.667 aclk = ~aclk; // 300 MHz clock
        //forever #8.138 aclk = ~aclk; // 61.44 MHz clock
        //forever #6.667 aclk = ~aclk; // 75 MHz clock
        forever #2.035 aclk = ~aclk; // 245.76 MHz clock
    end

    reg  [DATA_WIDTH-1:0] data_in; // 10ms 245.76Msps data
    integer j;
    initial begin
        // Wait for reset deassertion
        repeat(30) @(posedge aclk);
        // Write Operation
        data_in = 'h0;
        j = 0;
        // Wait for the tready handshake
        forever begin
            @(posedge aclk);
            while (!s_axis_tready) 
            repeat(1) @(posedge aclk);
            data_in = data_ram[j];
            if (j == Fs*Ts-1) 
                j = 0;
            else
                j = j + 1;
            s_axis_tvalid = 1;
        end
    end
    reg [47:0] reg_date = 0;
    initial begin
        // Wait for reset deassertion
        forever begin
            @(posedge aclk);
            reg_date = reg_date + 32'h4444_4444;
        end
    end

    // Test Procedure
    initial begin
        // Reset
        #10
        s_axi_aresetn = 0;
        #10;
        s_axi_aresetn = 1;
        m_axis_tready_w = 1;
        
        // Wait for reset deassertion
        repeat(10) @(posedge s_axi_aclk);
        forever begin
            @(posedge aclk);
            reg_date = reg_date + 32'h4444_4444;
            write_address(32'h8000_C000, reg_date[47:16]);//-50MHz
            write_address(32'h8000_C004, reg_date[15:0]);
        end
        //write_address(32'h8000_C000, 32'h344A_AAAA);//50.2MHz
        //write_address(32'h8000_C004, 32'hAAAA);
        //write_address(32'h8000_C000, 32'h8000_0000);//122.88MHz
        //write_address(32'h8000_C004, 32'h0000);
        
        //repeat(10) @(posedge s_axi_aclk);
        //read_address(32'h8000_C000);
    end
    /*
    // 定义存储器数组（4个地址，每个地址8位）
    reg  [DATA_WIDTH-1:0] out_mem[0:Fs*Ts-1]; // 10ms 245.76Msps data
    integer k;
    integer file_handle;
    initial begin
        // 检查文件是否可写入
        file_handle = $fopen("/home/fulin.zhang/ctrx_5g/projects/k7/xpt60/output_data_dsx4.txt", "w");
        if (file_handle == 0) begin
            $display("[ERROR] Unable write to output_data_dsx4.txt");
            $finish;
        end
        $fclose(file_handle);

        k = 0;
        while(k < Fs*Ts) begin
            @(posedge aclk);
            if (m_axis_tvalid && m_axis_tready) begin
                out_mem[k] = m_axis_tdata;
                k = k + 1;
            end else begin
                k = k;
            end
        end
        repeat(2) @(posedge aclk); // 等待仿真运行一段时间（确保数据已更新）
        $writememh("/home/fulin.zhang/ctrx_5g/projects/k7/xpt60/output_data_dsx4.txt", out_mem); // 写入全部数据
        $display("completed writing output_data_dsx4.txt");
    end
    */
    // 定义存储器数组（4个地址，每个地址8位）
    reg  [DATA_WIDTH-1:0] out_mem_dsx4[0:Fs*Ts-1]; // 10ms 245.76Msps data
    integer n;
    integer file_handle;
    initial begin
        // 检查文件是否可写入
        file_handle = $fopen("/home/fulin.zhang/ctrx_5g/projects/k7/xpt60/output_data.txt", "w");
        if (file_handle == 0) begin
            $display("[ERROR] Unable write to output_data.txt");
            $finish;
        end
        $fclose(file_handle);

        n = 0;
        while(n < Fs*Ts) begin
            @(posedge aclk);
            if (m_axis_tvalid_w && m_axis_tready_w) begin
                out_mem_dsx4[n] = m_axis_tdata_w;
                n = n + 1;
            end else begin
                n = n;
            end
        end
        repeat(2) @(posedge aclk); // 等待仿真运行一段时间（确保数据已更新）
        $writememh("/home/fulin.zhang/ctrx_5g/projects/k7/xpt60/output_data.txt", out_mem_dsx4); // 写入全部数据
        $display("completed writing output_data.txt");
    end

    //----------- Begin Cut here for INSTANTIATION Template ---// INST_TAG
    design_1 design_1_i(
        .aclk_0                 (aclk                    ),
        .aresetn_0              (s_axi_aresetn           ),
        
        .s_axis_0_tdata         (data_in                 ),
        .s_axis_0_tready        (s_axis_tready           ),
        .s_axis_0_tvalid        (s_axis_tvalid           ),

        .s_axi_aclk_0           (s_axi_aclk              ),
        .s_axi_0_awvalid        (s_axi_awvalid           ),
        .s_axi_0_awaddr         (s_axi_awaddr            ),
        .s_axi_0_awprot         (s_axi_awprot            ),
        .s_axi_0_awready        (s_axi_awready           ),

        .s_axi_0_wvalid         (s_axi_wvalid            ),
        .s_axi_0_wdata          (s_axi_wdata             ),
        .s_axi_0_wstrb          (s_axi_wstrb             ),
        .s_axi_0_wready         (s_axi_wready            ),

        .s_axi_0_bvalid         (s_axi_bvalid            ),
        .s_axi_0_bresp          (s_axi_bresp             ),
        .s_axi_0_bready         (s_axi_bready            ),

        .s_axi_0_arvalid        (s_axi_arvalid           ),
        .s_axi_0_araddr         (s_axi_araddr            ),
        .s_axi_0_arprot         (s_axi_arprot            ),
        .s_axi_0_arready        (s_axi_arready           ),

        .s_axi_0_rvalid         (s_axi_rvalid            ),
        .s_axi_0_rdata          (s_axi_rdata             ),
        .s_axi_0_rresp          (s_axi_rresp             ),
        .s_axi_0_rready         (s_axi_rready            ),
        
        .m_axis_0_tdata         (m_axis_tdata_w          ),
        .m_axis_0_tready        (m_axis_tready_w         ),
        .m_axis_0_tvalid        (m_axis_tvalid_w         ));
    // INST_TAG_END ------ End INSTANTIATION Template ---------
    /*
    //----------- Begin Cut here for INSTANTIATION Template ---// INST_TAG
    fir_downsample_x4#(
        .SWAP_IQ                (1                       )) 
    fir_downsample_x4_i(
        .aclk                   (aclk                    ),
        .aresetn                (s_axi_aresetn           ),
        
        .s_axis_tdata           (m_axis_tdata_w          ),
        .s_axis_tready          (m_axis_tready_w         ),
        .s_axis_tvalid          (m_axis_tvalid_w         ),

        .m_axis_tdata           (m_axis_tdata            ),
        .m_axis_tready          (m_axis_tready           ),
        .m_axis_tvalid          (m_axis_tvalid           ));
    // INST_TAG_END ------ End INSTANTIATION Template ---------
    */
    // task read_address;
    task read_address;
        input [31:0] addr;  // 
        begin
            if (addr[31:12] == 20'h8000_C) begin
                //**********************************step 3: read 0x8006_0000 *******************************
                // Read Operation
                s_axi_araddr = addr;   // Address to read
                s_axi_arprot = 3'b010;       // Protection type
                s_axi_arvalid = 1;           // Indicate address valid
                s_axi_rready = 1;            // Indicate ready for response
                
                // Wait for the address handshake
                @(posedge s_axi_aclk);
                while (!s_axi_arready) @(posedge s_axi_aclk);
                s_axi_arvalid = 0;           // Deassert valid after handshake
                
                // Wait for the read data
                @(posedge s_axi_aclk);
                while (!s_axi_rvalid) @(posedge s_axi_aclk);
                s_axi_rready = 0;            // Deassert after receiving data
                repeat(20) @(posedge s_axi_aclk);
            end
            //$display("Read from address %h: data = %h", addr, data); 
        end
    endtask
    // task write_address;
    task write_address;
        input [31:0] addr;      
        input [31:0] data_val;  
        begin
            //**********************************step 1: write 0x1 to 0x8006_0000***************
            // Write Operation
            if (addr[31:12] == 20'h8000_C) begin
                s_axi_awaddr = addr;   // Address to write
                s_axi_awprot = 3'b010;       // Protection type
                s_axi_awvalid = 1;           // Indicate address valid
                s_axi_wdata = data_val;        // Data to write
                s_axi_wstrb = 4'b1111;       // Write strobes
                s_axi_wvalid = 1;            // Indicate data valid
                s_axi_bready = 1;            // Indicate ready for response
                
                // Wait for the address handshake
                @(posedge s_axi_aclk);
                while (!s_axi_awready) @(posedge s_axi_aclk);
                s_axi_awvalid = 0;           // Deassert valid after handshake

                // Wait for the write data handshake
                while (!s_axi_wready) @(posedge s_axi_aclk);
                s_axi_wvalid = 0;            // Deassert valid after handshake

                @(posedge s_axi_aclk);
                while (!s_axi_bvalid) @(posedge s_axi_aclk);
                s_axi_bready = 0;            // Deassert after receiving response
                repeat(10) @(posedge s_axi_aclk);
            end 
        end
    endtask
endmodule
